/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>

#include <mc/common.h>
#include <mc/dict.h>
#include <mc/memory.h>

#include "../../../../../drivers/pcie_nic_card/hisi/interface/board.h"

namespace {

// Test fixture
class board_test : public ::testing::Test {
protected:
    void SetUp() override {
        m_board = mc::make_shared<dev::Board>();
    }

    void TearDown() override {
        m_board.reset();
    }

    mc::shared_ptr<dev::Board> m_board;
};

// ========== replace_dynamic_property 测试 ==========

TEST_F(board_test, replace_dynamic_property_replaces_slot_placeholder) {
    // 测试正常情况：Slot 是 "${Slot}"，应该被替换
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", "${Slot}"}};

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 5);
}

TEST_F(board_test, replace_dynamic_property_does_not_replace_non_placeholder) {
    // 测试 Slot 不是 "${Slot}"，不应该被替换
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", static_cast<uint8_t>(3)}};

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    // Slot 应该保持原值 3，而不是被替换为 5
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 3);
}

TEST_F(board_test, replace_dynamic_property_does_not_replace_string_slot) {
    // 测试 Slot 是字符串但不是 "${Slot}"，不应该被替换
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", "Slot1"}};

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    // Slot 应该保持原值 "Slot1"
    EXPECT_EQ(board_obj["Slot"].as<std::string>(), "Slot1");
}

TEST_F(board_test, replace_dynamic_property_handles_missing_slot) {
    // 测试 board_obj 不包含 "Slot"，不应该处理
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{{"OtherProperty", "value"}};

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    // board_obj 不应该包含 "Slot"
    EXPECT_FALSE(board_obj.contains("Slot"));
    EXPECT_EQ(board_obj["OtherProperty"].as<std::string>(), "value");
}

TEST_F(board_test, replace_dynamic_property_handles_different_slot_values) {
    // 测试不同的 Slot 值
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", "${Slot}"}};

    mc::dict connector{{"Slot", static_cast<uint8_t>(0)}};

    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 0);

    // 测试另一个值
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", "${Slot}"}};
    connector               = mc::dict{{"Slot", static_cast<uint8_t>(255)}};

    m_board->replace_dynamic_property(object, connector);

    board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 255);
}

TEST_F(board_test, replace_dynamic_property_preserves_other_properties) {
    // 测试替换 Slot 时保留其他属性
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{
        {"Slot", "${Slot}"},
        {"Manufacturer", "HUAWEI"},
        {"Model", "TestBoard"},
    };

    mc::dict connector{{"Slot", static_cast<uint8_t>(2)}};

    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 2);
    EXPECT_EQ(board_obj["Manufacturer"].as<std::string>(), "HUAWEI");
    EXPECT_EQ(board_obj["Model"].as<std::string>(), "TestBoard");
}

TEST_F(board_test, replace_dynamic_property_handles_empty_board_obj) {
    // 测试空的 board_obj
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{};

    mc::dict connector{{"Slot", static_cast<uint8_t>(5)}};

    // 应该不会崩溃
    m_board->replace_dynamic_property(object, connector);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    // board_obj 应该仍然是空的
    EXPECT_FALSE(board_obj.contains("Slot"));
}

TEST_F(board_test, replace_dynamic_property_handles_multiple_replacements) {
    // 测试多次调用 replace_dynamic_property
    mc::mutable_dict object;
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", "${Slot}"}};

    mc::dict connector1{{"Slot", static_cast<uint8_t>(1)}};
    m_board->replace_dynamic_property(object, connector1);

    auto board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 1);

    // 再次设置占位符并替换
    object["bmc.dev.Board"] = mc::mutable_dict{{"Slot", "${Slot}"}};
    mc::dict connector2{{"Slot", static_cast<uint8_t>(2)}};
    m_board->replace_dynamic_property(object, connector2);

    board_obj = object["bmc.dev.Board"].as<mc::mutable_dict>();
    EXPECT_EQ(board_obj["Slot"].as<uint8_t>(), 2);
}

} // namespace

